/***************************************************************************
 *   mgpi_math.h - Mathematical Calulations Declarations                   *
 *   Copyright (C) 2008 by cmaster.matso                                   *
 *   cmaster.matso@gmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef _MATH_H
#define _MATH_H

#ifdef __cplusplus
extern "C" {
#endif

#include <math.h>
#include "mgpi_gpuc.h"

#define MGPI_PI 3.141592653589793                                               /** Pi number */

#define MGPI_IDENTITY { \
	{ 1.0f, 0, 0, 0 },\
	{ 0, 1.0f, 0, 0 },\
	{ 0, 0, 1.0f, 0 },\
	{ 0, 0, 0, 1.0f },\
		 }																		/** an identity matrix */

#define MGPI_DEFAULT_VECTOR { 0.0f, 0.0f, 0.0f, 1.0f }                          /** default uniform vector */
#define MGPI_ZERO_ONE   1                                                       /** 0 to 1 clamping mode */
#define MGPI_MINUS_ONE_ONE  0                                                   /** -1 to 1 clamping mode */

    typedef float float2[2];                                                    /** 2-by-1 float matrix */
    typedef float float3[3];                                                    /** 3-by-1 float matrix */
    typedef float float4[4];                                                    /** 4-by-1 float matrix */
    typedef float float3x3[3][3];                                               /** 3-by-3 float matrix */
    typedef float float4x4[4][4];                                               /** 4-by-4 float matrix */
    typedef float4 quat_t;                                                      /** quaternion */
    typedef float * floatn;                                                     /** n-by-1 float matrix */
    typedef float ** matrix_t;                                                  /** n-by-m float matrix */

    /**
     * Sets the given value as min value in clamping.
     */
    float MGPI_API MGPI_Min(float v);

    /**
     * Sets the given value as max value in clamping.
     */
    float MGPI_API MGPI_Max(float v);

    /**
     * Calculates length for the given vector.
     */
    float MGPI_API MGPI_VecLength(float4 v);

    /**
     * Clamps the given value according to the set max and min values
     * and to the selected clamping range (-1 to 1 or 0 to 1).
     */
    float MGPI_API MGPI_Clamp(float v);

    /**
     * Unclamps the given value according to the set max and min values
     * and to the selected clamping range (-1 to 1 or 0 to 1).
     */
    float MGPI_API MGPI_Unclamp(float v);

    /**
     * Sets the clamp mode to the given.
     */
    void MGPI_API MGPI_ClampMode(int mode);

    /**
     * Calculates k-norm for the given vector.
     */
    float MGPI_API MGPI_NormK(floatn v, int k, int n);

#define MGPI_NormOne(v,n) (MGPI_NormK(v,1,n))
#define MGPI_NormQuad(v,n) (MGPI_NormK(v,2,n))
#define MGPI_NormEuklid MGPI_NormQuad

    /**
     * Calculates infinitive norm for the given vector.
     */
    float MGPI_API MGPI_NormInfinity(floatn v, int n);

    /**
     * Calculates cross product for two given vectors.
     */
    float4 MGPI_API *MGPI_CrossProduct(float4 *product, float4 a, float4 b);

    /**
     * Calculates dot product for two given vectors.
     */
    float MGPI_API MGPI_DotProduct(float3 a, float3 b);

    /**
     * Normalizes the given vector by dividing it by its length.
     */
    float4 MGPI_API *MGPI_Normalize(float4 *v);

    /**
     * Makes the given float3 vector uniform by dividing it by its Z component.
     */
    float3 MGPI_API *MGPI_Uniform3(float3 *v);

    /**
     * Makes the given float4 vector uniform by dividing it by its W component.
     */
    float4 MGPI_API *MGPI_Uniform4(float4 *v);

    /**
     * Multiplies two 3-by-3 matrices.
     */
    float3x3 MGPI_API *MGPI_MatrixMul3(float3x3 *product, float3x3 a, float3x3 b);

    /**
     * Multiplies two 4-by-4 matrices.
     */
    float4x4 MGPI_API *MGPI_MatrixMul4(float4x4 *product, float4x4 a, float4x4 b);

    /**
     * Multiplies 3-by-3 matrix with float3 vector (left side).
     */
    float3 MGPI_API *MGPI_MatrixMulVect3(float3 *product, float3x3 m, float3 v);

    /**
     * Multiplies 3-by-3 matrix with float3 vector (right side).
     */
    float3 MGPI_API *MGPI_VectorMulMatr3(float3 *product, float3 v, float3x3 m);

    /**
     * Multiplies 4-by-4 matrix with float4 vector (left side).
     */
    float4 MGPI_API *MGPI_MatrixMulVect4(float4 *product, float4x4 m, float4 v);

    /**
     * Multiplies 4-by-4 matrix with float4 vector (left side).
     */
    float4 MGPI_API *MGPI_VectorMulMatr4(float4 *product, float4 v, float4x4 m);

    /**
     * Transposes the given 4-by-4 matrix.
     */
    float4x4 MGPI_API *MGPI_TranspMatr4x4(float4x4 *m);

    /**
     * Converts the given 4-by-4 matrix to float array.
     */
    float MGPI_API *MGPI_ToArray16(float4x4 *m);

    /**
     * Converts the given float array to 4x4 matrix.
     */
    float MGPI_API **MGPI_ToArray4x4(float *m);

    /**
     * Transposes the given 3-by-3 matrix.
     */
    float3x3 MGPI_API *MGPI_TranspMatr3x3(float3x3 *m);

    /**
     * Converts the given 3-by-3 matrix to float array.
     */
    float MGPI_API *MGPI_ToArray9(float3x3 *m);

    /**
     * Converts the given float array to 3-by-3 matrix.
     */
    float MGPI_API **MGPI_ToArray3x3(float *m);

    /**
     * Multiplies two n-by-n matrices.
     */
    matrix_t MGPI_API *MGPI_MatrixMuln(matrix_t *product, matrix_t a, matrix_t b, int n);

    /**
     * Multiplies m-by-n matrix with n-by-m one.
     */
    matrix_t MGPI_API *MGPI_MatrixMulmn(matrix_t *product, matrix_t a, matrix_t b, int n, int m);

    /* Quaternions */
    /**
     * Multiplies two quaternions.
     */
    quat_t MGPI_API *MGPI_MulQuats(quat_t *product, quat_t q, quat_t p);

    /**
     * Converts the given quaternion to its reciprocal.
     */
    quat_t MGPI_API *MGPI_ReciprocalQuat(quat_t *product, quat_t q);

    /**
     * Converts the given quaternion to its conjugate.
     */
    quat_t MGPI_API *MGPI_ConjugateQuat(quat_t *product, quat_t q);

    /**
     * Calculate a square norm of the given quaternion.
     */
    float MGPI_API MGPI_QuatSqrNorm(quat_t q);

#define MGPI_TranspMatr9(matr) (MGPI_ToArray9(MGPI_TranspMatr3x3(&MGPI_ToArray3x3(matr))))      /** matrix transposition macro for 3x3 matrices */
#define MGPI_TranspMatr16(matr) (MGPI_ToArray16(MGPI_TranspMatr4x4(&MGPI_ToArray4x4(matr))))    /** matrix transposition macro for 4x4 matrices */

#ifdef __cplusplus
}
#endif

#endif
